/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 * Tray function http://docs.oracle.com/javase/6/docs/api/java/awt/SystemTray.html
 */
package form;

import form.DialogFX.Type;
import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.scene.control.MenuItem;
import javafx.application.Application;
import javafx.scene.control.CheckBoxTreeItem.TreeModificationEvent;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableMap;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Callback;
import javafx.util.Pair;
import javax.imageio.ImageIO;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;

import services.Command;
import services.Command.ResponseCode;
import services.Host;
import services.Packet;
import services.ResearchFile;

import side.ExpandList;
import side.JacksonStream;
import side.exComparator;
import side.listFile;
import thread.DiscoveryThreadClient;
import thread.FileCheckThread;

/**
 *
 * @author Barbara Sołtysiak
 */
public class GUI extends Application {

    public Stage stage;
    public Scene scene;
    public AnchorPane anchorPane, anchorPane2;
    public ObservableMap<String, Object> elements;
    public FXMLLoader loader;
    public static TreeView tree;
    public TreeView userTree;
    public MenuBar menuBar;
    public Menu file;
    public MenuItem folderToShare, folderToDownload, close;
    public TreeItem<String> rootItem, userItem, temp, tempT;
    public Button send, copy, refresh;
    public ComboBox comboBox;
    public static String PathForShare;
    public static List<ResearchFile> fileToSend = new ArrayList<ResearchFile>();
    // public static ArrayList<Pair<TreeItem<String>,String>> expandList = new ArrayList<Pair<TreeItem<String>,String>>();
    public static ArrayList<ExpandList> expandList = new ArrayList<ExpandList>();
    //Button przycik = (Button) elementy.get("");
    Image imageDecline;
    public static listFile lf = new listFile();
    static String MD5;
    //Flags
    public static boolean refreshFlag, MD5Flag, listingFlag, copyFlag, sendFlag, lock, syntaxFlag, removeFlag;
    private TrayIcon trayIcon;
    public static int prevhostSize, counter;
    public static ArrayList<Pair<CheckBoxTreeItem<String>, CheckBoxTreeItem<String>>> pair;
    EventHandler<TreeModificationEvent<String>> evtH;
    private boolean firstTime;

    @Override
    @SuppressWarnings("empty-statement")
    public void start(Stage stage) throws IOException {


        imageDecline = new Image(getClass().getResourceAsStream("refresh2.png"));

        MD5Flag = false;
        listingFlag = false;
        copyFlag = false;
        sendFlag = false;
        refreshFlag = false;

        removeFlag = false;
        this.stage = stage;
        this.stage.setTitle("homemade FTP");

        this.stage.setResizable(false);
        this.stage.getIcons().add(new Image(getClass().getResourceAsStream("logo.png")));
        createTrayIcon(this.stage);
        firstTime = true;
        GUI.counter = 0;
        Platform.setImplicitExit(false);


        loader = new FXMLLoader(getClass().getResource("/graphics/GUIv2.fxml"));
        try {
            anchorPane = (AnchorPane) loader.load();
            elements = loader.getNamespace();


        } catch (Exception e) {
            System.out.println("Now in GUI thread: " + e.getMessage());
        }

        anchorPane2 = (AnchorPane) elements.get("anchorPane");
        tree = (TreeView) elements.get("tree");
        tempT = new CheckBoxTreeItem("Hosts");


        copy = (Button) elements.get("copy");
        send = (Button) elements.get("send");
        comboBox = (ComboBox) elements.get("comboBox");
        //      comboBox.setEditable(true);
        menuBar = (MenuBar) elements.get("barMenu");
        file = (Menu) elements.get("file");
        folderToShare = (MenuItem) elements.get("folderToShare");
        folderToDownload = (MenuItem) elements.get("folderToDownload");
        close = (MenuItem) elements.get("close");
        refresh = (Button) elements.get("refresh");
        //  tree.setShowRoot(false);
        userTree = (TreeView) elements.get("userTree");
        userTree.setEditable(true);
        userTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        tree.setEditable(true);
        tree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        final DropShadow shadow = new DropShadow();
        pair = new ArrayList<Pair<CheckBoxTreeItem<String>, CheckBoxTreeItem<String>>>();

        for (Host h : Command.clientList) {
            System.out.append(h.getName() + "   ");
        }


        Image imageDecline = new Image(getClass().getResourceAsStream("refresh2.png"));

        refresh.setGraphic(new ImageView(imageDecline));
        refresh.addEventHandler(MouseEvent.MOUSE_CLICKED,
                new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent t) {
                thread.DiscoveryThreadClient.first = true;
                if (comboBox.getValue() != null) {
                    String s = comboBox.getValue().toString();
                    comboBox.getItems().clear();
                    for (Host h : Command.clientList) {
                        comboBox.getItems().add(h.getName());
                        if (h.getName().equals(s)) {
                            comboBox.setValue(s);
                            setTree(tree, tree.getRoot(), s);
                        }
                    }
                } else {
                    comboBox.getItems().clear();
                    for (Host h : Command.clientList) {
                        comboBox.getItems().add(h.getName());

                    }
                }


            }
        });
        copy.addEventHandler(MouseEvent.MOUSE_CLICKED,
                new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent t) {
                System.out.append("****************" + "\n");
                ArrayList l = new ArrayList();
                if (Command.def.getFileToCopy() == null) {
                    Command.def.setFileToCopy(new ArrayList<ResearchFile>());
                }
                for (Host h : Command.clientList) {


                    if (h.getPair() != null && h.getFile() != null) {

                        Iterator IT = h.getPair().iterator();
                        int size = h.getPair().size();
                        for (int i = 0; i < size; i++) {


                            Pair<CheckBoxTreeItem<String>, CheckBoxTreeItem<String>> p =
                                    (Pair<CheckBoxTreeItem<String>, CheckBoxTreeItem<String>>) h.getPair().get(i);
                            System.out.append(p.getKey().toString() + " " + String.valueOf(size) + "\n");

                            //jeżeli u hosta lokalnego występują takie same pliki jak te, które chce skopiować
                            for (ResearchFile rf : h.getFile()) {
                                //
                                if ((!rf.isIsDirectory() && h.getName().trim().equals(p.getValue().getValue().trim()))
                                        || (!rf.isIsDirectory() && rf.getAbsolutePath().trim().contains(p.getValue().getValue().trim()))) {
                                    if (rf.getName().trim().equals(p.getKey().getValue().trim())) {
                                        Command.def.setFileToCopy(rf);
                                    }
                                    for (ResearchFile r : Command.def.getFile()) {
                                        if (rf.getName().equals(r.getName())) {
                                            if (!Command.def.getFileToCopy().contains(rf)) {
                                            }
                                            //  System.out.append("dodano plik do wyslania " + rf.getName() + "\n");
                                        }
                                    }
                                }

                            }
                            System.out.append(h.getName() + ": " + p.getKey().getValue() + "\t" + p.getValue().getValue() + "\n");
                        }
                    } else {
                        System.out.append(h.getName() + " is empty " + "\n");
                    }

                }

                File f = new File("fileToCopy.json");
                if (f.exists()) {
                    f.delete();
                } else {
                    try {

                        side.JacksonStream.createJsonFile("fileToCopy", Command.def.getFileToCopy());
                    } catch (JsonGenerationException ex) {
                        Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (JsonMappingException ex) {
                        Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IOException ex) {
                        Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

                copyFlag = true;
                System.out.append("COPYFLAG " + copyFlag + "\n");

            }
        });
        copy.addEventHandler(MouseEvent.MOUSE_ENTERED,
                new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                copy.setEffect(shadow);

            }
        });
        copy.addEventHandler(MouseEvent.MOUSE_EXITED,
                new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                copy.setEffect(null);
            }
        });

        refresh.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                setTree(userTree, userItem, Command.def.getName());
                for (Host h : Command.clientList) {
                    comboBox.getItems().add(h.getName());
                }
            }
        });

        send.addEventHandler(MouseEvent.MOUSE_CLICKED,
                new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent t) {
                if (GUI.pair == null || GUI.pair.isEmpty()) {
                    DialogFX dialog = new DialogFX(Type.INFO);
                    dialog.setTitleText("Informacja");
                    dialog.addStylesheet("styleSheet.css");
                    dialog.setMessage("Brak wybranych elementów do wysłania");
                    dialog.showDialog();
                } else {
                    sendFlag = true;
                }

            }
        });
        send.addEventHandler(MouseEvent.MOUSE_ENTERED,
                new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                send.setEffect(shadow);
            }
        });
        send.addEventHandler(MouseEvent.MOUSE_EXITED,
                new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                send.setEffect(null);
            }
        });

        close.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {

                sharefiles.ShareFiles.GUIflag = false;
                DatagramSocket c;
                try {
                    c = new DatagramSocket();
                    c.setBroadcast(true);
                    c.setSoTimeout(4000);
                    byte[] sData = Packet.generatePacketAsString(Command.ClientType.CLIENT, Command.MessageType.INFO, Command.Include.INFO, ResponseCode.QUIT.name()).getBytes();
                    DatagramPacket sendPacket = new DatagramPacket(sData, sData.length, InetAddress.getByName("255.255.255.255"), 4444);
                    c.send(sendPacket);
                } catch (Exception ex) {
                    Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.append("Wysłano pakiet o wyjściu\n");
                deleteFile();
                Platform.exit();
                System.exit(0);
                //    Thread.currentThread().interrupt();
            }
        });



        folderToShare.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                String path = "."; // path to the directory to be opened  
                File file = new File("C:\\defaultSharedFiles");
                Desktop desktop = null;
// Before more Desktop API is used, first check  
// whether the API is supported by this particular  
// virtual machine (VM) on this particular host.  
                if (Desktop.isDesktopSupported()) {
                    desktop = Desktop.getDesktop();
                }
                try {
                    desktop.open(file);
                } catch (IOException ex) {
                }
            }
        });



        File file = new File("C:\\defaultSharedFiles");
        PathForShare = file.getPath();
        if (file.exists()) {
            File[] allfiles = file.listFiles();
            ArrayList<ResearchFile> fileList = new ArrayList<ResearchFile>();
            try {
                GUI.traverse(file, fileList);
                File f = new File("default.json");
                if (f.exists()) {
                    f.delete();
                    System.out.println("file was deleted... ");
                    JacksonStream.createJsonFile("default", fileList);
                    System.out.println("and created again\n");
                } else {
                    JacksonStream.createJsonFile("default", fileList);


                }
            } catch (IOException ex) {
                Logger.getLogger(GUI.class
                        .getName()).log(Level.SEVERE, null, ex);
            }
        } else if (!file.exists()) {

            file.mkdir();
            System.out.println("\nmkdir\n");
            File[] allfiles = file.listFiles();
            for (File f : allfiles) {
                //      System.out.append(f.toString() + "\n");
            }
        }

        MD5 = "first-value";
        Thread discoveryThreadClient = new Thread(DiscoveryThreadClient.getInstance());
        discoveryThreadClient.start();

        userTree.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<CheckBoxTreeItem<String>>() {
            @Override
            public void changed(ObservableValue<? extends CheckBoxTreeItem<String>> ov, CheckBoxTreeItem<String> t, CheckBoxTreeItem<String> t1) {
                // System.out.append(getClass().getName() + ">>> " + t1.isLeaf() + "\t" + t1.getParent().getValue() + "\n");
                try {
                    System.out.append(t1.getValue() + " " + t1.isSelected().booleanValue() + "\n");

                } catch (NullPointerException ex) {
                }
            }
        });
        EventHandler<TreeModificationEvent<String>> evtHandler = new EventHandler<TreeModificationEvent<String>>() {
            @Override
            public void handle(TreeModificationEvent event) {
                if (event.wasSelectionChanged()) {
                    if (event.getTreeItem().isSelected().booleanValue()) {
                        event.getTreeItem().setSelected(true);
                        Pair p = new Pair(event.getTreeItem(), event.getTreeItem().getParent());
                        if (!pair.contains(p)) {
                            pair.add(p);
                        }
                        System.out.append(event.getTreeItem().getValue().toString() + " " + event.getTreeItem().isSelected() + "\n");
                    } else {
                        Pair p = new Pair(event.getTreeItem(), event.getTreeItem().getParent());
                        if (pair.contains(p)) {
                            pair.remove(p);
                        }
                        event.getTreeItem().setSelected(false);
                        System.out.append(event.getTreeItem().getValue().toString() + " " + event.getTreeItem().isSelected() + "\n");
                    }
                } else if (event.wasIndeterminateChanged()) {
                } else {
                    event.getTreeItem().setSelected(true);
                    Pair p = new Pair(event.getTreeItem(), event.getTreeItem().getParent());
                    if (!pair.contains(p)) {
                        pair.add(p);
                    }
                    //          System.out.append(event.getTreeItem().getValue().toString() + "\n");
                }
            }
        };
        if (Command.def == null) {
            Command.def = new Host(InetAddress.getLocalHost().getHostName(), InetAddress.getLocalHost().getHostAddress());
        }
        userItem = new CheckBoxTreeItem(Command.def.getName());
        userItem.addEventHandler(CheckBoxTreeItem.<String>checkBoxSelectionChangedEvent(), evtHandler);
        // listen to selection changes (including to indeterminate state)

        tree.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<CheckBoxTreeItem<String>>() {
            @Override
            public void changed(ObservableValue<? extends CheckBoxTreeItem<String>> ov, CheckBoxTreeItem<String> t, CheckBoxTreeItem<String> t1) {
            }
        });

        evtH = new EventHandler<TreeModificationEvent<String>>() {
            @Override
            public void handle(TreeModificationEvent event) {
                if (event.wasSelectionChanged()) {

                    if (event.getTreeItem().isSelected().booleanValue()) {
                        event.getTreeItem().setSelected(true);
                        Pair p = new Pair(event.getTreeItem(), event.getTreeItem().getParent());
                        System.out.append(event.getTreeItem().getValue().toString() + " " + event.getTreeItem().isSelected() + "\n");
                        for (Host h : Command.clientList) {

                            if (h.getName().contains(tree.getRoot().getValue().toString().trim())) {
                                if (h.getPair() == null) {
                                    h.setPair(new ArrayList<Pair<CheckBoxTreeItem<String>, CheckBoxTreeItem<String>>>());
                                    h.setPair(p);
                                    System.out.append("Dla " + h.getName() + " dodano parę :" + event.getTreeItem() + "  " + event.getTreeItem().getParent() + "\n");
                                } else if (!h.getPair().contains(p)) {
                                    h.setPair(p);
                                    System.out.append("Dla " + h.getName() + " dodano parę :" + event.getTreeItem() + "  " + event.getTreeItem().getParent() + "\n");

                                }
                                for (Pair k : h.getPair()) {
                                    System.out.println("Para dla: " + h.getName() + "to: " + k.getKey() + " wyżej to: " + k.getValue());
                                }
                            }
                        }

                    } else {
                        Pair p = new Pair(event.getTreeItem(), event.getTreeItem().getParent());
                        for (Host h : Command.clientList) {

                            if (h.getPair().contains(p)) {
                                h.removePair(p);
                                System.out.append("Dla " + h.getName() + " USUNIĘTO parę :" + event.getTreeItem() + "  " + event.getTreeItem().getParent());

                            }
                        }
                        event.getTreeItem().setSelected(false);
                        System.out.append(event.getTreeItem().getValue().toString() + " " + event.getTreeItem().isSelected() + "\n");
                    }
                } else if (event.wasIndeterminateChanged()) {
                } else {
                    event.getTreeItem().setSelected(true);
                    Pair p = new Pair(event.getTreeItem(), event.getTreeItem().getParent());
                    for (Host h : Command.clientList) {
                        if (!h.getPair().contains(p)) {
                            h.setPair(p);
                        }
                    }
                    //         System.out.append(event.getTreeItem().getValue().toString() + "\n");
                }
            }
        };


        userTree.setRoot(userItem);

        userItem.setExpanded(true);
        lf.listFile(".json");

        setTree(userTree, userItem, Command.def.getName());
        if (Command.clientList.isEmpty() || Command.clientList == null) {
            createRootItem("Brak klientów w sieci", evtH);
        }
        tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());

        prevhostSize = Command.clientList.size();

        for (ResearchFile r : Command.def.getFile()) {
            System.out.append(getClass().getSimpleName() + ":>> " + r.getName() + "\n");
        }

        userTree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());

        comboBox.setCellFactory(
                new Callback<ListView<String>, ListCell<String>>() {
            @Override
            public ListCell<String> call(ListView<String> param) {
                final ListCell<String> cell = new ListCell<String>() {
                    {
                        super.setPrefWidth(100);

                    }

                    @Override
                    public void updateItem(String item,
                            boolean empty) {
                        super.updateItem(item, empty);
                        if (item != null) {
                            setText(item);
                            setFont(Font.font("Verdena", FontWeight.BOLD, 12));

                        } else {
                            setText("Nobody");
                        }
                    }
                };
                return cell;
            }
        });
        comboBox.getItems().clear();
        for (Host h : Command.clientList) {
            comboBox.getItems().add(h.getName());
        }
        comboBox.valueProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue ov, String t, String t1) {
                System.out.println(ov);
                System.out.println(t);
                System.out.println("nowa wartość!!");

                if (t1 != null) {
                    createRootItem(t1, evtH);
                    System.out.println(t1);
                    if (tree.getRoot() != null) {
                        for (Host h : Command.clientList) {
                            if (h.getName().equals(t1)) {
                                setTree(tree, tree.getRoot(), t1);
                                if (h.getPair() != null) {
                                    compareTree(tree.getRoot(), h.getPair());
                                }
                            }
                        }
                    }
                } else {
                    System.out.println("t1 jest nullem");
                    createRootItem(t, evtH);
                    System.out.println(t);
                    if (tree.getRoot() != null) {
                        for (Host h : Command.clientList) {
                            if (h.getName().equals(t)) {
                                setTree(tree, tree.getRoot(), t);
                                if (h.getPair() != null) {
                                    compareTree(tree.getRoot(), h.getPair());
                                }
                            }
                        }
                    }
                }
            }
        });

        scene = new Scene(anchorPane);
        stage.setScene(scene);
        stage.show();


        DialogFX dialog = new DialogFX(Type.INFO);
        dialog.setTitleText("Informacja");
        dialog.addStylesheet("styleSheet.css");

        dialog.setMessage("Twój domyślny folder z plikami to C:\\defaultSharedFiles");
        dialog.showDialog();
        File f = new File(Command.def.getIp() + ".json");
        System.out.println(Command.def.getName() + Command.def.getIp() + ".json \n");
        if (!f.exists()) {
            JacksonStream.createJsonFile(Command.def.getIp(), Command.def.getFile());
            System.out.append("Utworzono ponownie plik: " + Command.def.getIp() + ".json\n");

        } else {
            JacksonStream.createJsonFile(Command.def.getIp(), Command.def.getFile());
            System.out.append("Utworzono ponownie plik: " + Command.def.getIp() + ".json\n");

        }


        sharefiles.ShareFiles.fileCheckThread = new Thread(FileCheckThread.getInstance());
        sharefiles.ShareFiles.fileCheckThread.start();

        startScheduledExecutorService();
    }

    /*
     * Tworzenie drzewa na podstawie nazwy name
     * Użytkownik wyszukiwany jest we wszystkich elementach typu Host. Ze struktury pobierana jest lista jego plików
     * po czym umieszcza się ją na drzewie. 
     */
    public void setTree(TreeView tr, TreeItem<String> rootNode, String name) {

        Host h = null;
        rootNode.setExpanded(true);
        rootNode.getChildren().clear();


        if (Command.def != null) {
            if (Command.def.getName().contains(name.trim())) {
                h = Command.def;
            }
        }
        if (!Command.clientList.isEmpty()) {

            for (Host host : Command.clientList) {
                if (host.getName().contains(name.trim())) {
                    h = host;
                }

            }
        }
        expandList.clear();
        lf.listFile(".json");
        if (h.getFile() != null) {

            for (ResearchFile rf : h.getFile()) {

                if (rf.isIsDirectory() == true) {

                    //Directory
                    String n = "\\" + rf.getName();
                    String pathUp = rf.getAbsolutePath().replace(n, "");
                    //    System.out.println(pathUp + "\n");

                    CheckBoxTreeItem<String> cat = new CheckBoxTreeItem<String>(rf.getName());
                    cat.setExpanded(false);

                    expandList.add(new ExpandList(cat, pathUp, rf.getAbsolutePath()));
                    if (expandList.isEmpty()) {
                        rootNode.getChildren().add(cat);
                    }
                    for (ExpandList e : expandList) {

                        //do item.getChildren() nie działa!!!
                        if (e.getAbsolutePath() == pathUp) {
                            System.out.println("YES\t");
                            System.out.println(e.getAbsolutePath() + "\t" + pathUp + "\n");
                            for (int i = 0; i < rootNode.getChildren().size(); i++) {
                                if (rootNode.getChildren().get(i) == e.getDir()) {
                                    rootNode.getChildren().get(i).getChildren().add(cat);
                                }
                            }
                        }
                    }

                }
            }
            ExpandList[] listaObiektowArray = new ExpandList[expandList.size()];
//konwertowanie do Array
            expandList.toArray(listaObiektowArray);
//tworzenie nowego comparatora
            exComparator comp = new exComparator();
//ackaj sortowania
            Arrays.sort(listaObiektowArray, comp);
//konwertujemy spowrotem na Listę obiektów
            List<ExpandList> posortowanaLista = Arrays.asList(listaObiektowArray);
            for (ExpandList e : posortowanaLista) {

                rootNode.getChildren().add(new CheckBoxTreeItem<String>(e.getDir().getValue()));
            }

            for (ResearchFile rf : h.getFile()) {
                if (rf.isIsDirectory() == false) {
                    String n = "\\" + rf.getName();
                    String pathUp = rf.getAbsolutePath().replace(n, "");

                    CheckBoxTreeItem<String> file = new CheckBoxTreeItem<String>(rf.getName());

                    //                System.out.println(getClass().getName() + ">>> " + rf.getName() + "\t" + pathUp + "\n");
                    file.setExpanded(true);
                    if (expandList.isEmpty() || pathUp.trim().equals(PathForShare)) {

                        rootNode.getChildren().add(file);
                    }
                    for (ExpandList e : expandList) {
                        //     System.out.println(getClass().getName() + ">>> " + rf.getName());
                        if (e.getAbsolutePath().equals(pathUp)) {
                            for (int i = 0; i < rootNode.getChildren().size(); i++) {
                                if (rootNode.getChildren().get(i).getValue() == e.getDir().getValue()) {

                                    rootNode.getChildren().get(i).getChildren().add(file);

                                }
                            }
                        } else {
                        }
                    }

                    //      rootNode.getChildren().add(file);
                }
            }


        }


    }
    /*
     * funkcja przeglądająca zawartość katalogu rekursywnie i zapisująca wszystko to listy typu ResearchFile
     */

    public static void traverse(File f, ArrayList<ResearchFile> fileList) throws IOException {

        if (f != null) {

            File[] allfiles = f.listFiles();
            if (allfiles != null) {

                for (File x : allfiles) {
                    if (x.isDirectory()) {
                        fileList.add(new ResearchFile(x.getName(), x.getAbsolutePath(), x.getPath(), x.length(), true));
                        File[] childs = x.listFiles();
                        for (File child : childs) {
                            traverse(child, fileList);
                            if (child.isDirectory()) {
                                System.out.println(child.getPath() + "\n");
                                fileList.add(new ResearchFile(child.getName(), child.getAbsolutePath(), child.getPath(), child.length(), true));
                            } else {
                                fileList.add(new ResearchFile(child.getName(), child.getAbsolutePath(), child.getPath(), child.length(), false));
                            }
                        }
                        continue;
                    } else {
                        fileList.add(new ResearchFile(x.getName(), x.getAbsolutePath(), x.getPath(), x.length(), false));

                    }
                }
            }
        }
    }

    void setupGestureSource(final TreeView source) {

        source.setOnDragDetected(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                /* drag was detected, start drag-and-drop gesture*/
                System.out.println("onDragDetected");

                /* allow any transfer mode */
                Dragboard db = source.startDragAndDrop(TransferMode.COPY);

                /* put a string on dragboard */
                ClipboardContent content = new ClipboardContent();
//               content.putString(source.getText());

                db.setContent(content);

                event.consume();
            }
        });

        source.setOnDragDone(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                /* the drag-and-drop gesture ended */
                System.out.println("onDragDone");
                /* if the data was successfully moved, clear it */
                if (event.getTransferMode() == TransferMode.MOVE) {
//                   source.setText("");
                }

                event.consume();
            }
        });

    }

    void setupGestureTarget(final TreeView target) {

        target.setOnDragOver(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                System.out.println("onDragOver");
                if (event.getGestureSource() != target
                        && event.getDragboard().hasString()) {
                    event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
                }

                event.consume();
            }
        });

        target.setOnDragEntered(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                System.out.println("onDragEntered");
                if (event.getGestureSource() != target
                        && event.getDragboard().hasString()) {
                }

                event.consume();
            }
        });

        target.setOnDragExited(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                /* mouse moved away, remove the graphical cues */
                //    target.setFill(Color.BLACK);

                event.consume();
            }
        });

        target.setOnDragDropped(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {

                System.out.println("onDragDropped");
                Dragboard db = event.getDragboard();
                boolean success = false;
                if (db.hasString()) {
                    //   target.setText(target.getRoot().getValue() + "\n" + db.getString());
                    success = true;
                }

                event.setDropCompleted(success);

                event.consume();
            }
        });

    }

    static public void listingTree() {

        File file = new File(PathForShare);
        if (file.exists()) {
            File[] allfiles = file.listFiles();
            ArrayList<ResearchFile> fileList = new ArrayList<ResearchFile>();

            try {
                GUI.traverse(file, fileList);
                if (Command.def.getFile() == null) {
                    Command.def.setFile(new ArrayList<ResearchFile>());
                }
                Command.def.setFile(fileList);

                lock = true;
                File f = new File("default.json");
                if (f.exists()) {
                    f.delete();
                    //      System.out.println("file was deleted\n");
                    JacksonStream.createJsonFile("default", fileList);
                    //      System.out.println("New file was added\n");
                    lock = false;
                } else {
                    JacksonStream.createJsonFile("default", fileList);
                    //     System.out.println("New file was added\n");
                    lock = false;


                }
            } catch (IOException ex) {
                Logger.getLogger(GUI.class
                        .getName()).log(Level.SEVERE, null, ex);
            }

        }

    }
    /*
     * Tworzy korzeń drzewa w zalezności od nadanego parametru name
     * Do każdego nowego korzenia zostaje dodany EventHandler dla możliwości wyboru CheckBoxa
     */

    public void createRootItem(String name, EventHandler evtH) {
        CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>(name);
        rootItem.addEventHandler(CheckBoxTreeItem.<String>checkBoxSelectionChangedEvent(), evtH);
        tree.setRoot(rootItem);
    }
    /*
     * Porównanie drzewa i nazw zaznaczonych plików. Funkcja używana przy ponownym tworzeniu drzew
     * 
     */

    public static void compareTree(TreeItem<String> t1, ArrayList<Pair<CheckBoxTreeItem<String>, CheckBoxTreeItem<String>>> pair) {
        ArrayList<Pair<CheckBoxTreeItem<String>, CheckBoxTreeItem<String>>> pa = pair;
        for (Pair p : pa) {

            CheckBoxTreeItem<String> tiKey = (CheckBoxTreeItem) p.getKey();
            CheckBoxTreeItem<String> tiValue = (CheckBoxTreeItem) p.getValue();
            //      System.out.append(tiKey.getValue() + "\t" + tiValue.getValue() + "\n");
            Iterator it = t1.getChildren().iterator();
            while (it.hasNext()) {
                CheckBoxTreeItem<String> c = (CheckBoxTreeItem<String>) it.next();
                if (!c.getChildren().isEmpty() && c.getValue().trim().equals(tiValue.getValue().trim())) {
                    Iterator it2 = c.getChildren().iterator();
                    while (it2.hasNext()) {
                        CheckBoxTreeItem<String> c2 = (CheckBoxTreeItem<String>) it2.next();
                        if (c2.getValue().trim().equals(tiKey.getValue().trim())) {
                            //if(c.equals(tiKey))
                            c2.setSelected(true);
                            System.out.append(c2.getValue() + " " + c2.isSelected().booleanValue() + " podkatalog\n");

                        }
                    }
                }
                //      System.out.append(c.getValue() + "\t" + tiKey.getValue()+ "\n");
                if (c.getValue().trim().equals(tiKey.getValue().trim())) {
                    //if(c.equals(tiKey))
                    c.setSelected(true);
                    System.out.append(c.getValue() + " " + c.isSelected().booleanValue() + " rowne\n");

                }
            }
        }

    }

    public void createTrayIcon(final Stage stage) {
        if (SystemTray.isSupported()) {
            // get the SystemTray instance
            SystemTray tray = SystemTray.getSystemTray();
            // load an image
            java.awt.Image image = null;


            try {
                URL url = getClass().getResource("active.png");
                image = ImageIO.read(url);


            } catch (IOException ex) {
                Logger.getLogger(GUI.class
                        .getName()).log(Level.SEVERE, null, ex);
            }


            stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
                @Override
                public void handle(WindowEvent t) {
                    hide(stage);
                }
            });
            // create a action listener to listen for default action executed on the tray icon
            final ActionListener closeListener = new ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent e) {

                    sharefiles.ShareFiles.GUIflag = false;
                    deleteFile();
                    DatagramSocket c;
                    try {
                        c = new DatagramSocket();
                        c.setBroadcast(true);
                        c.setSoTimeout(4000);
                        byte[] sData = Packet.generatePacketAsString(Command.ClientType.CLIENT, Command.MessageType.INFO, Command.Include.INFO, ResponseCode.QUIT.name()).getBytes();
                        DatagramPacket sendPacket = new DatagramPacket(sData, sData.length, InetAddress.getByName("255.255.255.255"), 4444);
                        c.send(sendPacket);



                    } catch (Exception ex) {
                        Logger.getLogger(GUI.class
                                .getName()).log(Level.SEVERE, null, ex);
                    }
                    System.out.append("Wysłano pakiet o wyjściu\n");
                    deleteFile();
                    Platform.exit();
                    System.exit(0);
                }
            };

            ActionListener showListener = new ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent e) {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            stage.show();
                        }
                    });
                }
            };
            // create a popup menu
            PopupMenu popup = new PopupMenu();

            java.awt.MenuItem showItem = new java.awt.MenuItem("Pokaż");
            showItem.addActionListener(showListener);
            popup.add(showItem);

            java.awt.MenuItem closeItem = new java.awt.MenuItem("Zamknij");
            closeItem.addActionListener(closeListener);
            popup.add(closeItem);
            /// ... add other items
            // construct a TrayIcon
            trayIcon = new TrayIcon(image, "homemade FTP", popup);
            // set the TrayIcon properties
            trayIcon.addActionListener(showListener);
            // ...
            // add the tray image
            try {
                tray.add(trayIcon);
            } catch (AWTException e) {
                System.err.println(e);
            }
            // ...
        }
    }

    public void showProgramIsMinimizedMsg() {
        if (firstTime) {
            trayIcon.displayMessage("UWAGA",
                    "Aplikacja nie uległa zamknięciu",
                    TrayIcon.MessageType.INFO);
            firstTime = false;
        }

    }

    private void hide(final Stage stage) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                if (SystemTray.isSupported()) {
                    stage.hide();
                    showProgramIsMinimizedMsg();
                } else {
                    sharefiles.ShareFiles.GUIflag = false;
                    DatagramSocket c;
                    try {
                        c = new DatagramSocket();
                        c.setBroadcast(true);
                        c.setSoTimeout(4000);
                        byte[] sData = Packet.generatePacketAsString(Command.ClientType.CLIENT, Command.MessageType.INFO, Command.Include.INFO, ResponseCode.QUIT.name()).getBytes();
                        DatagramPacket sendPacket = new DatagramPacket(sData, sData.length, InetAddress.getByName("255.255.255.255"), 4444);
                        c.send(sendPacket);



                    } catch (Exception ex) {
                        Logger.getLogger(GUI.class
                                .getName()).log(Level.SEVERE, null, ex);
                    }
                    System.out.append("Wysłano pakiet o wyjściu\n");
                    deleteFile();
                    System.exit(0);
                }
            }
        });
    }

    public void deleteFile() {

        File dir = new File(".//");

        if (dir.isDirectory() == false) {
            System.out.println("Directory does not exists : ");
            return;
        }

        String[] list = dir.list();
        if (list.length == 0) {
            System.out.println("no files end with : " + ".json");
            return;
        }
        for (String ff : list) {

            if (ff.contains(".json")) {
                File fi = new File(ff);
                if (fi.exists()) {
                    fi.deleteOnExit();
                    System.out.append("\nSkasowano plik o nazwie: " + ff);
                }

            }
        }

    }

    public static GUI getInstance() {
        return DiscoveryThreadHolder.INSTANCE;


    }

    private static class DiscoveryThreadHolder {

        private static final GUI INSTANCE = new GUI();
    }

    private void startScheduledExecutorService() throws IOException {

        final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        scheduler.scheduleAtFixedRate(
                new Runnable() {
            int hostSize;
            String inMD5, outMD5;
            boolean b = false;
            ArrayList<Pair<String, String>> p = new ArrayList<Pair<String, String>>();

            @Override
            public void run() {
                //             System.out.append("PrevHost size is: " + String.valueOf(prevhostSize) + "\n");
                hostSize = Command.clientList.size();

                //             System.out.append("Host size is: " + String.valueOf(hostSize) + "\n");
                GUI.counter++;
                if (counter % 20 == 0) {
                    System.out.append("Counter: " + String.valueOf(GUI.counter) + "\n");
                }
                if (removeFlag) {
                    if (comboBox.getValue().toString() != null) {
                        for (Host h : Command.clientList) {
                            if (h.getName().equals(comboBox.getValue().toString())) {
                                setTree(tree, tree.getRoot(), comboBox.getValue().toString());
                                if (h.getPair() != null) {
                                    compareTree(tree.getRoot(), h.getPair());
                                }

                            }
                        }
                    } else {
                        if (Command.clientList.isEmpty() || Command.clientList == null) {
                            createRootItem("Brak klientów w sieci", evtH);

                        }

                    }
                    removeFlag = false;
                }
                if (GUI.listingFlag) {
                    setTree(userTree, userTree.getRoot(), Command.def.getName());
                }

                if ((prevhostSize != hostSize) || GUI.listingFlag) {
                    if(GUI.listingFlag){
                        
                    }
                    if (comboBox.getItems().isEmpty()) {
                        
                        System.out.append("Prev: " + prevhostSize + " :: hostSize: " + hostSize + "\n");
                    }
                    if (!Command.clientList.isEmpty()) {
                        System.out.append("Prev: " + prevhostSize + " :: hostSize: " + hostSize + "\n");
                        //     setTree(userTree,userTree.getRoot(), Command.def.getName());
                       
                        //          comboBox.getItems().clear();
                        System.out.append("Prev: " + prevhostSize + " :: hostSize: " + hostSize + "\n");
                        if (!Command.clientList.isEmpty() && (prevhostSize != hostSize) ) {
                                System.out.append("Prev: " + prevhostSize + " :: AAA: " + hostSize + "\n");
                            if(!comboBox.getItems().isEmpty()){
                                    System.out.append("Prev: " + prevhostSize + " :: BBB: " + hostSize + "\n");
                                comboBox.getItems().clear();
                            }
                            for (Host h : Command.clientList) {
                                System.out.append("Prev: " + prevhostSize + " :: CCC: " + hostSize + "\n");
                                comboBox.getItems().add(h.getName());
                            }
                        }
                        System.out.append("Aktualizacja comboboxa :" + String.valueOf(GUI.counter) + "\n");
                        if (comboBox.getValue() == null) {
                            System.out.append("ComboBox jest pusty" + "\n");

                        } else {
                            System.out.append("Wartość wybrana :" + comboBox.getValue().toString() + "\n");

                            lf.listFile(".json");

                            for (Host h : Command.clientList) {
                                if (h.getName().equals(comboBox.getValue().toString())) {
                                    System.out.append("Wartość wybrana 11111 :" + comboBox.getValue().toString() + "\n");
                                    setTree(tree, tree.getRoot(), comboBox.getValue().toString());
                                    if (!h.getPair().isEmpty()) {
                                        System.out.append("Wartość wybrana 2222 :" + comboBox.getValue().toString() + "\n");
                                       // compareTree(tree.getRoot(), h.getPair());
                                    }

                                }
                            }
                            System.out.append("Wartość wybrana  3333333:" + comboBox.getValue().toString() + "\n");
                            tree.getRoot().setExpanded(true);
                        }
                    }
                    prevhostSize = hostSize;
                    GUI.listingFlag = false;
                    System.out.append("Koniec przetwarzania drzewa\n");
                }

                if (lock) {
                    side.SideDish.wait(500);
                    try {
                        inMD5 = side.SideDish.md5("default.json");
                    } catch (IOException ex) {
                        Logger.getLogger(GUI.class
                                .getName()).log(Level.SEVERE, null, ex);
                    }
                } else {
                    try {

                        inMD5 = side.SideDish.md5("default.json");


                    } catch (IOException ex) {
                        Logger.getLogger(GUI.class
                                .getName()).log(Level.SEVERE, null, ex);
                    }
                }

                //  System.out.append("WYSKOCZYŁO: " + inMD5 + "\n");
                //   System.out.append("WYSKOCZYŁO 22: " + outMD5 + "\n");
// System.out.append("GUIcountera\n");
                if (GUI.counter == 1) {
                    outMD5 = inMD5.trim();
                    System.out.append("now in is out\n");
                }
                //    System.out.append("refreshflag\n");
                if (refreshFlag) {
                    System.out.append("USERRRRR\n");
                    userTree.getRoot().getChildren().clear();
                                        System.out.append("USERRRRR 2\n");

                    setTree(userTree, userTree.getRoot(), Command.def.getName());
                                        System.out.append("USERRRRR 3\n");

                    compareTree(userTree.getRoot(), pair);
                    System.out.append("TREEEEE\n");
                    if (tree.getRoot() != null) {
                        for (Host h : Command.clientList) {
                            if (h.getName().equals(comboBox.getValue().toString())) {
                                setTree(tree, tree.getRoot(), comboBox.getValue().toString());
                                if (h.getPair() != null) {
                                    compareTree(tree.getRoot(), h.getPair());
                                }
                            }
                        }
                    }
                       System.out.append("TREEEEE  2\n");

                }
                //      System.out.append("MD5\n");
                if (!outMD5.equals(inMD5.trim())) {
                    GUI.MD5Flag = true;
                    System.out.append("Zmieniono MD5: " + MD5Flag + "\n");
                    setTree(userTree, userItem, Command.def.getName());

                    System.out.append(outMD5 + "\n" + inMD5 + "\n");
                    outMD5 = inMD5.trim();
                    System.out.append("after\n");
                    lf.listFile(".json");

                    userTree.getRoot().setExpanded(true);
                    if (!pair.isEmpty()) {
                        compareTree(userTree.getRoot(), pair);
                    }
                    System.out.append("Size of userTree: " + String.valueOf(userTree.getRoot().getChildren().size()) + "\n");

                }
            }
        },
                1,
                1,
                TimeUnit.SECONDS);
    }
}
